

function observe(obj) {
    for (const key in obj) {
        let internalValue = obj[key];
        let funcs = new Set();
        Object.defineProperty(obj, key, {
            get: function() {
                // 依赖收集， 记录：哪个函数在用我
                // 假设 函数 是存在 window 上面的
                if (window.__func) {
                    funcs.add(window.__func);
                }
                return internalValue;
            },
            set: function(newVal) {
                internalValue = newVal;
                // 派发更新， 运行：执行用我的函数
                funcs.forEach(func => func())
            },
        })
    }
}

// 自动运行函数，实现依赖收集的时候，将函数记录在一个全局变量中（这里以window全局变量为例）
function autoRun(func) {
    window.__func = func;
    func();
    window.__func = null;
}


/**
 * 简单实现原理：
 * 执行 user.name = 'newName' 时，会自动运行与其相关的函数
 * 1. 修改属性值时，会调用set方法，设置新的值赋值给局部变量internalValue，还会会重新调用依赖该属性的函数，
 * 2. 调用这些函数后，函数内部又依赖于该属性，又会调用get方法，把internalValue返回，从而实现数据的响应式变化
 */



/**
 * 数据响应式：当数据发生变化时，会自动运行与其相关的函数
 * 1. 实现数据劫持，当数据发生变化时，自动通知依赖它的函数进行更新
 * 2. 实现依赖收集，将函数记录在一个数组中，当数据发生变化时，自动运行数组中的函数
 * 3. 实现派发更新，将函数数组中的函数依次执行，从而实现数据变化的通知
 */